package com.zhkj.crawl.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhkj.crawl.config.okhttp.CustomCookieJar;
import com.zhkj.crawl.config.okhttp.NetInterceptor;
import com.zhkj.crawl.config.okhttp.SSLSocketFactoryUtils;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
public class OkHttpPool {
    private static OkHttpClient globalClient;
    private static OkHttpClient proxyClient;
    public static Proxy forwardProxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(Constants.PROXY_HOST, Constants.PROXY_PORT));
    private static Integer proxyType = null;
    public static void setTypeForward(){
        proxyType = 1;
    }
    public static void setTypeZhiMa(){
        proxyType = 2;
    }


    public static OkHttpClient getOkHttpClient() {
        return getOkHttpClient(null, Proxy.Type.HTTP);
    }
    public static OkHttpClient getOkHttpClient(String proxyStr) {
        return getOkHttpClient(proxyStr, Proxy.Type.HTTP);
    }
    public static OkHttpClient getOkHttpClient(String proxyStr, Proxy.Type proxyType) {
        try{
            OkHttpClient client = null;
            if(StringUtils.isNotBlank(proxyStr)){
                // TODO
                proxyStr = "tps149.kdlapi.com:15818";

                if(proxyClient == null){
                    String[] split = proxyStr.split(":");
                    String proxyIp = split[0];
                    int proxyPort = Integer.parseInt(split[1]);

                    proxyClient = new OkHttpClient().newBuilder().sslSocketFactory(SSLSocketFactoryUtils.createSSLSocketFactory(), SSLSocketFactoryUtils.createTrustAllManager())
                            .hostnameVerifier(new SSLSocketFactoryUtils.TrustAllHostnameVerifier())
                            .followRedirects(true)
                            .protocols(Collections.unmodifiableList(Arrays.asList(Protocol.HTTP_1_1/*, Protocol.HTTP_2*/)))
                            .addNetworkInterceptor(new NetInterceptor())
                            .proxy(new Proxy(proxyType, new InetSocketAddress(proxyIp, proxyPort)))
                            .proxyAuthenticator((route, response) -> {
                                String credential = Credentials.basic(Constants.PROXY_USERNAME, Constants.PROXY_PASSWORD);
                                return response.request().newBuilder()
                                        .header("Proxy-Authorization", credential)
                                        .build();
                            })
                            .cookieJar(new CustomCookieJar())
                            .build();
                }
                return proxyClient;
            }

            if(globalClient == null){
                globalClient = new OkHttpClient().newBuilder().sslSocketFactory(SSLSocketFactoryUtils.createSSLSocketFactory(), SSLSocketFactoryUtils.createTrustAllManager())
                        .hostnameVerifier(new SSLSocketFactoryUtils.TrustAllHostnameVerifier())
                        .followRedirects(true)
                        .protocols(Collections.unmodifiableList(Arrays.asList(Protocol.HTTP_1_1/*, Protocol.HTTP_2*/)))
                        .addNetworkInterceptor(new NetInterceptor())
                        .cookieJar(new CustomCookieJar())
                        .build()
                ;
            }
            return globalClient;
        }catch (Exception e){
            log.error("获取代理client出错 本次不使用代理,{}", proxyStr);
            return new OkHttpClient();
        }
    }

    private static LinkedList<String> queue = new LinkedList<>();
    private static synchronized void reloadQueue(Integer deep){
        if(queue.size() >= 15){ return; }
        ++deep;
        System.out.println("加载代理队列");
        String url = "http://http.tiqu.letecs.com/getip3?num=15&type=1&pro=&city=0&yys=0&port=11&time=1&ts=0&ys=0&cs=0&lb=1&sb=0&pb=45&mr=2&regions=";
        try {
            if(deep > 1){ TimeUnit.SECONDS.sleep(2); }

            String text = Jsoup.connect(url)
                    .ignoreContentType(true)
                    .get().body().text();

            try {
                JSONObject json = JSON.parseObject(text);
                String msg = json.getString("msg");
                String ip = msg.replace("请添加白名单", "");

                addWhiteList(ip);
                reloadQueue(deep);
                return;
            }catch (Exception ignore){ }

            String[] s = text.split(" ");
            Collections.addAll(queue, s);
            log.info("加载代理队列{}条 {}", s.length, text);
        } catch (IOException | InterruptedException e) {
            log.error("代理加载错误", e);
        }
    }


    private static String getFromPool(){
        if(queue.size() > 3){
            return queue.pop();
        }
        reloadQueue(0);
        return queue.pop();
    }

    private static Proxy getProxyFromPool(){
        String ip = getFromPool();
        String[] split = ip.split(StringPool.COLON);
        return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(split[0], Integer.parseInt(split[1])));
    }

    private static Map<String, Proxy> pool = new ConcurrentHashMap<>();
    public static Proxy get(){
        switch (proxyType){
            case 1:
                return forwardProxy;
            case 2:
                String threadName = Thread.currentThread().getName();
                Proxy s = pool.get(threadName);
                if(s != null){
                    return s;
                }
                Proxy proxy = getProxyFromPool();
                pool.put(threadName, proxy);
                return proxy;
            default:
                throw new RuntimeException("请先设置代理类型");
        }
    }

    /**
     * 代理不可用了 剔旧换新
     */
    public static synchronized boolean switchIp(){
        switch (proxyType){
            case 1:
                return true;
            case 2:
                String threadName = Thread.currentThread().getName();
                Proxy proxy = pool.get(threadName);
                if(proxy != null){
                    String ip = proxy.address().toString().replace(StringPool.SLASH, StringPool.EMPTY);
                    //queue.remove(ip);
                    Proxy newProxy = getProxyFromPool();
                    pool.put(threadName, newProxy);
                    log.info("换IP {} => {}", ip, newProxy.address().toString().replace(StringPool.SLASH, StringPool.EMPTY));
                    return true;
                }
                return false;
            default:
                throw new RuntimeException("请先设置代理类型");
        }
    }

    private static void addWhiteList(String ip){
        try {
            System.out.printf("添加ip白名单<%s>\n", ip);
            Jsoup.connect("https://wapi.http.linkudp.com/index/index/save_white?neek=598070&appkey=015b12cf538f5eed5db8443710d4b0e1&white=" + ip)
                    .ignoreContentType(true)
                    .get();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {

//        Proxy proxy = get();
//        System.out.println(proxy.address().toString().replace(StringPool.SLASH, StringPool.EMPTY));
//
//        Proxy proxy1 = get();
//        System.out.println(proxy1.address().toString().replace(StringPool.SLASH, StringPool.EMPTY));
//
//        switchIp();
//
//        int q = 10;
//        while (--q >0){
//            Proxy proxy2 = get();
//            System.out.println(proxy2.address().toString().replace(StringPool.SLASH, StringPool.EMPTY));
//        }
    }
}
